(function(w) {
    var eyeGridFactory = (function() {
        // eyeGrid object constructor
        var eyeGrid = function eyeGrid(config) {
            // private variables
            var _ = {
                element : null,// 绘制区域(canvas)
                datapoints : [],// 数据点集合
                colors : [],// 颜色集合
                diaphaneity : 0.5, // 网格透明度
                worker : 1, // 多线程并发数(即待画图的被试个数)
                screenWidth : 1440,// 屏幕宽度
                screenHeight : 900,// 屏幕高度
                rows : 10, // 网格行数
                columns : 10, // 网格列数
                showType : 0
            // 显示类型
            };

            this.get = function(key) {
                return _[key];
            };
            this.set = function(key, value) {
                _[key] = value;
            };

            /**
             * 画网格图
             */
            this.drawGrid = function(context2D, x, y, width, height, color, data) {
                context2D.fillStyle = color;
                context2D.globalAlpha = this.get("diaphaneity");
                context2D.fillRect(x, y, width, height);

                var value = this.getShowValue(data);
                context2D.fillStyle = "#ffffff";
                context2D.font = "bold 10px sans-serif";
                context2D.fillStyle = "#000000";

                var middleWidth = value.length * 3; // 长度乘以3倍可大致定位到中间
                if (middleWidth > width / 2) { // 最大不能超过网格范围
                    middleWidth = width / 2;
                }
                var middleHeight = 7;

                context2D.fillText(value, (x + width / 2) - middleWidth, (y + height / 2) + middleHeight); // middleWidth和middleHeight是为了输出到网格中间

            };

            this.getShowValue = function(data) {
                var type = this.get("showType");
                var value = "";
                if (type == 1) {
                    value = data.fixCount + ""; // 注视点个数
                } else if (type == 2) {
                    value = data.firstStart + "ms"; // 进入时间
                } else if (type == 3) {
                    value = data.hitCount + ""; // 结果命中数
                } else if (type == 4) {
                    value = data.hitCountRatio + "%";// 结果命中率
                } else if (type == 5) {
                    value = data.durationAvg + "ms"; // 平均持续时长
                } else {
                    value = data.duration + "ms"; // 默认显示: 持续时长
                }
                return value;
            };

            // configure the eyeGrid when an instance gets created
            this.configure(config);
            // and initialize it
            this.init();
        };

        // public functions
        eyeGrid.prototype = {
            configure : function(config) {
                var me = this;

                me.set("element", config.element || me.get("element"));
                me.set("datapoints", config.datapoints || me.get("datapoints"));
                me.set("colors", config.colors || me.get("colors"));
                me.set("diaphaneity", config.diaphaneity || me.get("diaphaneity"));
                me.set("worker", config.worker || me.get("worker"));
                me.set("screenWidth", config.screenWidth || me.get("screenWidth"));
                me.set("screenHeight", config.screenHeight || me.get("screenHeight"));
                me.set("rows", config.rows || me.get("rows"));
                me.set("columns", config.columns || me.get("columns"));
                me.set("showType", config.showType || me.get("showType"));
            },

            init : function() {
            },

            drawGridByFiaxtion : function() {
                var me = this;
                var context2D = me.get("element")[0].getContext("2d");
                var colors = me.get("colors");
                var worker = me.get("worker");
                var rows = me.get("rows");
                var columns = me.get("columns");
                var perWidth = me.get("screenWidth") / rows; // 每网格宽度
                var perHeight = me.get("screenHeight") / columns; // 每网格高度
                var objs = newPointModel(eval(me.get("datapoints")));

                /** 1. 按行/列 初始二维数组 */
                var muliDataList = new Array();
                for ( var k = 0; k < worker + 1; k++) { // 初始worker+1个二维数据,分别计算每个的统计结果值,最后一个二维数组存储汇总值
                    var data = [];
                    for ( var i = 0; i < rows; i++) {
                        data[i] = [];
                        for ( var j = 0; j < columns; j++) {
                            data[i][j] = {
                                duration : 0, // 持续时长
                                fixCount : 0, // 注视点个数
                                firstStart : null, // 进入时间
                                hitCount : 0, // 结果命中数
                                hitCountRatio : 0, // 结果命中率 =
                                // (结果命中数/总的结果数即worker)
                                durationAvg : 0, // 持续时长(平均) = 持续时长 / 结果命中数
                                leftPupilSize : 0, // 左眼平均瞳孔
                                rightPupilSize : 0, // 右眼平均瞳孔
                                store: [] // 支持的数据内容
                            };
                        }
                    }
                    muliDataList.push(data);
                }

                /** 2. 遍历结果数据集,计算所属的网格,进而计算统计值 */
                var dataX = 0;
                var dataY = 0;
                for ( var i = 0; i < worker; i++) {
                    var data = muliDataList[i];
                    for ( var j = 0; j < objs[i].length; j++) {
                        // Math.floor函数是向下取整函数
                        dataX = Math.floor(objs[i][j].x / perWidth);
                        dataY = Math.floor(objs[i][j].y / perHeight);

                        // 原始x和y数据可能出现负数,此处做个保护
                        if (dataX < 0) {
                            dataX = 0;
                        }
                        if (dataY < 0) {
                            dataY = 0;
                        }

                        // 对越界做个保护,当大于数组最大长度时,归为该数组最大值
                        if (dataX > (rows - 1)) {
                            dataX = rows - 1;
                        }
                        if (dataY > (columns - 1)) {
                            dataY = columns - 1;
                        }

                        // 对统计值进行计算
                        data[dataX][dataY].duration += objs[i][j].fixDur; // 持续时长：累加
                        if (data[dataX][dataY].firstStart == null) { // 进入时长：第一个
                            data[dataX][dataY].firstStart = objs[i][j].fixStart;
                        }
                        data[dataX][dataY].fixCount++; // 注视点个数：自增
                        data[dataX][dataY].leftPupilSize += objs[i][j].LPS; // 左眼平均瞳孔：累加
                        data[dataX][dataY].rightPupilSize += objs[i][j].RPS; // 右眼平均瞳孔：累加
                        data[dataX][dataY].store.push(objs[i][j]);
                    }
                }

                /** 3. 汇总每个结果统计后的网格数据 */
                var dataAll = muliDataList[worker];
                for ( var i = 0; i < rows; i++) { // 按行列汇总
                    for ( var j = 0; j < columns; j++) {
                        for ( var k = 0; k < worker; k++) { // 遍历每个结果
                            if (muliDataList[k][i][j].fixCount > 0) {
                                // 当该结果该网格内，统计的注视点个数大于0个时，才计入汇总值中

                                dataAll[i][j].duration += muliDataList[k][i][j].duration; // 持续时长：累加
                                dataAll[i][j].fixCount += muliDataList[k][i][j].fixCount; // 注视点个数：累加
                                if (muliDataList[k][i][j].firstStart != null) { // 进入时长：取最小的进入时间
                                    if (dataAll[i][j].firstStart == null) {
                                        dataAll[i][j].firstStart = muliDataList[k][i][j].firstStart;
                                    } else {
                                        if (muliDataList[k][i][j].firstStart < dataAll[i][j].firstStart) {
                                            dataAll[i][j].firstStart = muliDataList[k][i][j].firstStart;
                                        }
                                    }
                                }
                                dataAll[i][j].hitCount++; // 结果命中数：自增
                                dataAll[i][j].leftPupilSize += muliDataList[k][i][j].leftPupilSize; // 左眼平均瞳孔：累加
                                dataAll[i][j].rightPupilSize += muliDataList[k][i][j].rightPupilSize; // 右眼平均瞳孔：累加
                                dataAll[i][j].store = muliDataList[k][i][j].store;
                            }
                        }
                        // 对一个网格统计遍历结果完成后，再计算某些统计值
                        if (dataAll[i][j].fixCount > 0) { // Math.round四舍五入取整
                            dataAll[i][j].durationAvg = Math.round(dataAll[i][j].duration / dataAll[i][j].hitCount); // 平均持续时长
                            dataAll[i][j].hitCountRatio = Math.round(dataAll[i][j].hitCount / worker * 100); // 结果命中率

                            // 左眼平均瞳孔: 需按注视点个数平均
                            dataAll[i][j].leftPupilSize = Math.round(dataAll[i][j].leftPupilSize * 100 / dataAll[i][j].fixCount) / 100;
                            // 右眼平均瞳孔: 需按注视点个数平均
                            dataAll[i][j].rightPupilSize = Math.round(dataAll[i][j].rightPupilSize * 100 / dataAll[i][j].fixCount) / 100;
                        }
                    }
                }

                /** 4. 遍历汇总后的二维数组,计算最大值和最小值,按区间计算颜色 */
                var maxVal = dataAll[0][0].duration;
                var minVal = dataAll[0][0].duration;
                for ( var i = 0; i < rows; i++) {
                    for ( var j = 0; j < columns; j++) {
                        if (dataAll[i][j].duration > maxVal) {
                            maxVal = dataAll[i][j].duration;
                        }
                        if (dataAll[i][j] < minVal) {
                            minVal = dataAll[i][j].duration;
                        }
                    }
                }
                var colorLevel = (maxVal - minVal) / colors.length; // 每一颜色等级差值

                /** 5. 遍历每个网格,画图 */
                var colorIndex = 0;
                for ( var i = 0; i < rows; i++) {
                    for ( var j = 0; j < columns; j++) {
                        if (dataAll[i][j].duration > 0) { // 当大于0时才绘制
                            // colors取值说明: 当前值-最小值,除以等级差,取整即得到所属颜色区间
                            colorIndex = Math.floor((dataAll[i][j].duration - minVal) / colorLevel);
                            if (colorIndex > (colors.length - 1)) { // 对越界做个保护
                                colorIndex = colors.length - 1;
                            }
                            me.drawGrid(context2D, i * perWidth, j * perHeight, perWidth, perHeight, colors[colorIndex], dataAll[i][j]);
                        }
                    }
                }

                return dataAll;

            },
            clearup : function() {
            }
        };

        return {
            create : function(config) {
                return new eyeGrid(config);
            }
        };
    })();

    w.eyeGrid = w.eyeGridFactory = eyeGridFactory;
})(window);
